package com.es.demo;

import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.ClearScrollRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchScrollRequest;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.core.TimeValue;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.Scroll;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms.Bucket;
import org.elasticsearch.search.aggregations.metrics.TopHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.xcontent.XContentBuilder;
import org.elasticsearch.xcontent.XContentFactory;


import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Test {

    private static RestHighLevelClient client = null;

    private static SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSSX");

    public static void main(String[] args) {
        EsClient esClient = new EsClient("192.168.0.128",9200,"elastic","ht123213");
        client = esClient.getRhlClient();
        String indexName = "mytest1";
        //createDemoIndex(indexName);
        //putDocument(indexName);
        //deleteDocument(indexName,"8K7YB4oBfpToEaOZn3LQ");
        System.out.println(getAggregation(indexName));


        //DemoBO demoBO = boolGetDocument(indexName);
       // System.out.println(demoBO);
    }


    public static void createDemoIndex(String indexname) {
        CreateIndexRequest request = new CreateIndexRequest(indexname);
        try {
            //判断是否已存在该索引，如果存在则先删除
            GetIndexRequest exist = new GetIndexRequest(indexname);
            if (client.indices().exists(exist, RequestOptions.DEFAULT)) {
                DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indexname);
                client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
            }
            XContentBuilder builder = XContentFactory.jsonBuilder().startObject()
                    .startObject("properties")
                    .startObject("demoName")
                    .field("type", "text")
                    .field("analyzer", "keyword")
                    .endObject()
                    .startObject("demoValue")
                    .field("type", "text")
                    .field("analyzer", "keyword")
                    .endObject()
                    .startObject("demoNumber")
                    .field("type", "integer")
                    .endObject()
                    .startObject("demoTime")
                    .field("type", "date")
                    .endObject()
                    .endObject()
                    .endObject();
            request.mapping(builder);
            client.indices().create(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static DemoBO getDocument(String indexName) {
        DemoBO bo = new DemoBO();
        try {
            SearchRequest searchRequest = new SearchRequest(indexName);
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(QueryBuilders.matchAllQuery()).from(0).size(10).sort("demoTime", SortOrder.DESC);//查询全部文档用此方法
            //searchSourceBuilder.query(QueryBuilders.matchPhraseQuery(indexName, "abc")).from(0).size(10).sort("demoTime", SortOrder.DESC);
            searchRequest.source(searchSourceBuilder);
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
            SearchHits searchHits = searchResponse.getHits();
            if (searchHits.getTotalHits().value > 0) {
                for (SearchHit hit: searchHits) {
                    convertBo(bo, hit);
                }
            }
        } catch (IOException | ParseException e) {
            e.printStackTrace();
        }
        return bo;
    }


    public static void postDocument(String indexName) {
        try {
            IndexRequest indexRequest = new IndexRequest(indexName);
            //IndexRequest indexRequest = new IndexRequest(indexName).id(id);//如果你要自己定义文档ID的值，可以这么写，否则Elasticsearch会自动帮你生成一个，不过官方也是不建议让你来建。
            indexRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);//此句功能为立即刷新索引文档，不然你会在页面上发现我明明已经新增一个文档了，却要过个几秒钟再刷新页面才会显示出来。
            Map<String, Object> map = new HashMap<>();
            map.put("demoName", "我的");
            map.put("demoValue", "我的值");
            map.put("demoNumber", 3);
            map.put("demoTime", new Date());
            indexRequest.source(map);
            IndexResponse indexResponse = client.index(indexRequest, RequestOptions.DEFAULT);
            System.out.println(indexResponse);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }



    public static void putDocument(String indexName, String id) {
        try {
            UpdateRequest updateRequest = new UpdateRequest(indexName, id);
            updateRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);//跟上面新增文档那里一样的作用
            Map<String, Object> map = new HashMap<>();
            map.put("demoName", "def");
            map.put("demoValue", "456");
            map.put("demoNumber", 2);
            map.put("demoTime", sdf.format(new Date()));
            updateRequest.doc(map);
            client.update(updateRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    public static void deleteDocument(String indexName, String id) {
        try {
            DeleteRequest deleteRequest = new DeleteRequest(indexName, id);
            deleteRequest .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);//跟上面新增文档那里一样的作用
            client.delete(deleteRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    public static DemoBO boolGetDocument(String indexName) {
        DemoBO bo = new DemoBO();
        try {
            SearchRequest searchRequest = new SearchRequest(indexName);
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
            boolQueryBuilder.must(QueryBuilders.matchPhraseQuery("demoName", "abc"));
            boolQueryBuilder.should(QueryBuilders.matchPhraseQuery("demoValue", "123"));
            boolQueryBuilder.should(QueryBuilders.rangeQuery("demoNumber").gte(1)).should(QueryBuilders.rangeQuery("demoNumber").lte(5));
            searchSourceBuilder.query(boolQueryBuilder).from(0).size(10).sort("demoTime", SortOrder.DESC);
            searchRequest.source(searchSourceBuilder);
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
            SearchHits searchHits = searchResponse.getHits();
            if (searchHits.getTotalHits().value > 0) {
                for (SearchHit hit: searchHits) {
                    convertBo(bo, hit);
                }
            }
        } catch (IOException | ParseException e) {
            e.printStackTrace();
        }
        return bo;
    }


    public static List<DemoBO> getAggregation (String indexName) {
        List<DemoBO> list = new ArrayList<>();
        try {
            SearchRequest searchRequest = new SearchRequest(indexName);
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            AggregationBuilder aggregation = AggregationBuilders.terms("qc").field("demoName.keyword").size(10).subAggregation(AggregationBuilders.topHits("tj").sort("demoName.keyword", SortOrder.DESC).size(1));//"qc"和"tj"是自定义名称，可以自己取，"qc"那部分指的是去重，"tj"那部分指的是统计，相当于SQL查询中的Group by。
            searchSourceBuilder.query(QueryBuilders.matchPhraseQuery("demoValue", "123")).aggregation(aggregation).size(0);
            searchRequest.source(searchSourceBuilder);
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
            Terms terms = searchResponse.getAggregations().get("qc");
            for (Bucket b: terms.getBuckets()) {
                DemoBO bo = new DemoBO ();
                bo.setDemoName(b.getKeyAsString());
                TopHits top = b.getAggregations().get("tj");
                for (SearchHit hit: top.getHits()) {
                    if (hit.getSourceAsMap().get("demoValue") != null) {
                        bo.setDemoValue(hit.getSourceAsMap().get("demoValue").toString());
                    } else {
                        bo.setDemoValue("");
                    }
                }
                list.add(bo);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }


    public static List<DemoBO> getAllDocuments(String indexName) {
        List<DemoBO> list = new ArrayList<>();
        try {
            final Scroll scroll = new Scroll(TimeValue.timeValueMinutes(1L));
            SearchRequest searchRequest = new SearchRequest(indexName);
            searchRequest.scroll(scroll);
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(QueryBuilders.matchAllQuery()).size(1000);
            searchRequest.source(searchSourceBuilder);
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
            StringBuilder scrollId = new StringBuilder(searchResponse.getScrollId());
            SearchHits searchHits = searchResponse.getHits();
            while (searchHits.getHits() != null && searchHits.getTotalHits().value > 0) {
                for (SearchHit hit: searchHits) {
                    DemoBO bo = new DemoBO();
                    convertBo(bo,hit);
                    list.add(bo);
                }
                SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId.toString());
                scrollRequest.scroll(scroll);
                searchResponse = client.scroll(scrollRequest, RequestOptions.DEFAULT);
                scrollId.replace(0, scrollId.length(), searchResponse.getScrollId());
                searchHits = searchResponse.getHits();
            }
            ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
            clearScrollRequest.addScrollId(scrollId.toString());
            client.clearScroll(clearScrollRequest, RequestOptions.DEFAULT);
        } catch (IOException | ParseException e) {
            e.printStackTrace();
        }
        return list;
    }

    private static void convertBo(DemoBO bo, SearchHit hit) throws ParseException {
        if (hit.getSourceAsMap().get("demoName") != null) {
            bo.setDemoName((String) hit.getSourceAsMap().get("demoName"));
        }
        if (hit.getSourceAsMap().get("demoValue") != null) {
            bo.setDemoValue((String) hit.getSourceAsMap().get("demoValue"));
        }
        if (hit.getSourceAsMap().get("demoNumber") != null) {
            bo.setDemoNumber((Integer) hit.getSourceAsMap().get("demoNumber"));
        }
        if (hit.getSourceAsMap().get("demoTime") != null) {
            bo.setDemoTime(sdf.parse((String) hit.getSourceAsMap().get("demoTime")));
        }
    }
}
